{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Seaborn 核密度估计 (kdeplot) 完整教程\n",
    "\n",
    "本教程详细讲解 Seaborn 中核密度估计图的使用方法，包括基础绘图、带宽调整、曲线延伸、填充效果和累积分布。\n",
    "\n",
    "## 目录\n",
    "1. 基础核密度估计\n",
    "2. 带宽调整 (bw_adjust)\n",
    "3. 曲线延伸 (cut)\n",
    "4. 填充效果 (fill)\n",
    "5. 累积分布 (cumulative)\n",
    "6. 综合应用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# 设置样式\n",
    "sns.set_theme(style=\"whitegrid\")\n",
    "plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']\n",
    "plt.rcParams['axes.unicode_minus'] = False\n",
    "\n",
    "# 加载示例数据\n",
    "penguins = sns.load_dataset(\"penguins\")\n",
    "tips = sns.load_dataset(\"tips\")\n",
    "iris = sns.load_dataset(\"iris\")\n",
    "\n",
    "print(\"企鹅数据集预览：\")\n",
    "penguins.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 1. 基础核密度估计\n",
    "\n",
    "### 1.1 什么是核密度估计（KDE）？\n",
    "\n",
    "核密度估计是一种**非参数方法**，用于估计随机变量的概率密度函数。它通过在每个数据点放置一个核函数（通常是高斯核），然后求和得到平滑的密度曲线。\n",
    "\n",
    "**优点**：\n",
    "- 平滑连续，易于观察分布形态\n",
    "- 不受区间划分影响\n",
    "- 适合展示连续分布"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\")\n",
    "plt.title(\"企鹅鳍长度的核密度估计\", fontsize=14)\n",
    "plt.xlabel(\"鳍长度 (mm)\")\n",
    "plt.ylabel(\"密度\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 KDE vs 直方图对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
    "\n",
    "# 直方图\n",
    "sns.histplot(data=penguins, x=\"flipper_length_mm\", \n",
    "             stat='density', bins=20, ax=axes[0])\n",
    "axes[0].set_title(\"直方图（离散）\")\n",
    "\n",
    "# KDE\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", ax=axes[1])\n",
    "axes[1].set_title(\"核密度估计（平滑）\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 2. 带宽调整 (bw_adjust)\n",
    "\n",
    "### 2.1 带宽的概念\n",
    "\n",
    "**带宽（bandwidth）** 控制核函数的宽度，影响曲线的平滑程度：\n",
    "- 带宽**小**：曲线更贴近数据，细节更多，但可能过拟合\n",
    "- 带宽**大**：曲线更平滑，但可能丢失细节\n",
    "\n",
    "`bw_adjust` 是带宽的调整因子（默认为1）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n",
    "\n",
    "bw_values = [0.2, 0.5, 1.0, 2.0]\n",
    "for ax, bw in zip(axes.flat, bw_values):\n",
    "    sns.kdeplot(data=penguins, x=\"flipper_length_mm\", \n",
    "                bw_adjust=bw, ax=ax)\n",
    "    ax.set_title(f\"bw_adjust={bw}\")\n",
    "    ax.set_xlabel(\"鳍长度 (mm)\")\n",
    "    ax.set_ylabel(\"密度\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"观察：\")\n",
    "print(\"- bw_adjust=0.2: 曲线波动大，细节多\")\n",
    "print(\"- bw_adjust=2.0: 曲线平滑，整体趋势明显\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 带宽选择建议\n",
    "\n",
    "- **探索性分析**：使用默认值（1.0）\n",
    "- **数据量大**：可适当减小（0.5-0.8）\n",
    "- **数据量小**：可适当增大（1.2-1.5）\n",
    "- **展示整体趋势**：增大带宽\n",
    "- **展示细节**：减小带宽"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 3. 曲线延伸 (cut)\n",
    "\n",
    "### 3.1 cut 参数说明\n",
    "\n",
    "`cut` 参数控制曲线在数据范围之外延伸的程度，单位是带宽的倍数（默认为3）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n",
    "\n",
    "cut_values = [0, 1, 3, 5]\n",
    "for ax, cut_val in zip(axes.flat, cut_values):\n",
    "    sns.kdeplot(data=penguins, x=\"flipper_length_mm\", \n",
    "                cut=cut_val, ax=ax)\n",
    "    ax.set_title(f\"cut={cut_val}\")\n",
    "    ax.set_xlabel(\"鳍长度 (mm)\")\n",
    "    ax.axvline(penguins['flipper_length_mm'].min(), \n",
    "               color='red', linestyle='--', alpha=0.5, label='数据最小值')\n",
    "    ax.axvline(penguins['flipper_length_mm'].max(), \n",
    "               color='red', linestyle='--', alpha=0.5, label='数据最大值')\n",
    "    ax.legend()\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 cut 的应用场景\n",
    "\n",
    "- `cut=0`：曲线严格限制在数据范围内\n",
    "- `cut=3`（默认）：适度延伸，展示尾部特征\n",
    "- `cut` 较大：展示更多尾部信息"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 4. 填充效果 (fill)\n",
    "\n",
    "### 4.1 fill 参数\n",
    "\n",
    "设置 `fill=True` 填充曲线下方区域，增强视觉效果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
    "\n",
    "# 不填充\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", ax=axes[0])\n",
    "axes[0].set_title(\"fill=False (默认)\")\n",
    "\n",
    "# 填充\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", fill=True, ax=axes[1])\n",
    "axes[1].set_title(\"fill=True\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 分组填充"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(12, 6))\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", \n",
    "            hue=\"species\", fill=True, alpha=0.5)\n",
    "plt.title(\"不同企鹅物种的鳍长度分布（填充）\", fontsize=14)\n",
    "plt.xlabel(\"鳍长度 (mm)\")\n",
    "plt.ylabel(\"密度\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3 common_norm 参数\n",
    "\n",
    "当使用 `hue` 分组时，`common_norm` 控制是否使用相同的归一化：\n",
    "- `True`（默认）：所有组使用相同的归一化\n",
    "- `False`：每组独立归一化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
    "\n",
    "# 共同归一化\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", \n",
    "            hue=\"species\", fill=True, common_norm=True, ax=axes[0])\n",
    "axes[0].set_title(\"common_norm=True (相同归一化)\")\n",
    "\n",
    "# 独立归一化\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", \n",
    "            hue=\"species\", fill=True, common_norm=False, ax=axes[1])\n",
    "axes[1].set_title(\"common_norm=False (独立归一化)\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 5. 累积分布 (cumulative)\n",
    "\n",
    "### 5.1 累积分布函数（CDF）\n",
    "\n",
    "设置 `cumulative=True` 显示累积分布函数，表示小于等于某个值的概率。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
    "\n",
    "# 概率密度函数（PDF）\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", ax=axes[0])\n",
    "axes[0].set_title(\"概率密度函数 (PDF)\")\n",
    "axes[0].set_ylabel(\"密度\")\n",
    "\n",
    "# 累积分布函数（CDF）\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", \n",
    "            cumulative=True, ax=axes[1])\n",
    "axes[1].set_title(\"累积分布函数 (CDF)\")\n",
    "axes[1].set_ylabel(\"累积概率\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.2 CDF 的应用\n",
    "\n",
    "累积分布函数可以回答以下问题：\n",
    "- 有多少比例的数据小于某个值？\n",
    "- 中位数在哪里？（CDF=0.5的位置）\n",
    "- 四分位数在哪里？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", cumulative=True)\n",
    "\n",
    "# 标记中位数\n",
    "median = penguins['flipper_length_mm'].median()\n",
    "plt.axvline(median, color='red', linestyle='--', label=f'中位数: {median:.1f}')\n",
    "plt.axhline(0.5, color='red', linestyle='--', alpha=0.3)\n",
    "\n",
    "# 标记四分位数\n",
    "q25 = penguins['flipper_length_mm'].quantile(0.25)\n",
    "q75 = penguins['flipper_length_mm'].quantile(0.75)\n",
    "plt.axvline(q25, color='green', linestyle=':', label=f'Q1: {q25:.1f}')\n",
    "plt.axvline(q75, color='green', linestyle=':', label=f'Q3: {q75:.1f}')\n",
    "\n",
    "plt.title(\"累积分布函数与分位数\", fontsize=14)\n",
    "plt.xlabel(\"鳍长度 (mm)\")\n",
    "plt.ylabel(\"累积概率\")\n",
    "plt.legend()\n",
    "plt.grid(alpha=0.3)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.3 分组累积分布"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", \n",
    "            hue=\"species\", cumulative=True, linewidth=2)\n",
    "plt.title(\"不同物种的累积分布对比\", fontsize=14)\n",
    "plt.xlabel(\"鳍长度 (mm)\")\n",
    "plt.ylabel(\"累积概率\")\n",
    "plt.grid(alpha=0.3)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 6. 综合应用\n",
    "\n",
    "### 6.1 完整示例：鸢尾花数据分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n",
    "\n",
    "# 1. 基础 KDE\n",
    "sns.kdeplot(data=iris, x=\"sepal_length\", ax=axes[0, 0])\n",
    "axes[0, 0].set_title(\"基础核密度估计\")\n",
    "\n",
    "# 2. 填充 + 分组\n",
    "sns.kdeplot(data=iris, x=\"sepal_length\", hue=\"species\", \n",
    "            fill=True, alpha=0.5, ax=axes[0, 1])\n",
    "axes[0, 1].set_title(\"分组填充\")\n",
    "\n",
    "# 3. 调整带宽\n",
    "sns.kdeplot(data=iris, x=\"sepal_length\", hue=\"species\", \n",
    "            bw_adjust=0.5, ax=axes[1, 0])\n",
    "axes[1, 0].set_title(\"带宽调整 (bw_adjust=0.5)\")\n",
    "\n",
    "# 4. 累积分布\n",
    "sns.kdeplot(data=iris, x=\"sepal_length\", hue=\"species\", \n",
    "            cumulative=True, ax=axes[1, 1])\n",
    "axes[1, 1].set_title(\"累积分布函数\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.2 双变量 KDE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 8))\n",
    "sns.kdeplot(data=penguins, x=\"flipper_length_mm\", y=\"body_mass_g\", \n",
    "            fill=True, cmap=\"Blues\", thresh=0, levels=10)\n",
    "plt.title(\"双变量核密度估计：鳍长度 vs 体重\", fontsize=14)\n",
    "plt.xlabel(\"鳍长度 (mm)\")\n",
    "plt.ylabel(\"体重 (g)\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.3 多子图分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建多个特征的 KDE 对比\n",
    "fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n",
    "\n",
    "features = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']\n",
    "titles = ['喙长度', '喙深度', '鳍长度', '体重']\n",
    "\n",
    "for ax, feature, title in zip(axes.flat, features, titles):\n",
    "    sns.kdeplot(data=penguins, x=feature, hue=\"species\", \n",
    "                fill=True, alpha=0.5, ax=ax)\n",
    "    ax.set_title(f\"{title}分布\")\n",
    "    ax.set_xlabel(title)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "### KDE 参数选择指南\n",
    "\n",
    "1. **bw_adjust（带宽调整）**：\n",
    "   - 默认值（1.0）适合大多数情况\n",
    "   - 数据噪声大：增大至 1.5-2.0\n",
    "   - 需要细节：减小至 0.5-0.8\n",
    "\n",
    "2. **cut（曲线延伸）**：\n",
    "   - 默认值（3）通常足够\n",
    "   - 严格限制范围：设为 0\n",
    "   - 关注尾部：增大至 5\n",
    "\n",
    "3. **fill（填充）**：\n",
    "   - 单一分布：可选\n",
    "   - 多组对比：建议使用，配合 alpha\n",
    "\n",
    "4. **cumulative（累积）**：\n",
    "   - 分位数分析：使用\n",
    "   - 分布对比：使用\n",
    "   - 概率计算：使用\n",
    "\n",
    "### KDE vs 直方图\n",
    "\n",
    "**使用 KDE 的场景**：\n",
    "- 连续数据\n",
    "- 需要平滑曲线\n",
    "- 多组对比\n",
    "- 数据量充足（>50）\n",
    "\n",
    "**使用直方图的场景**：\n",
    "- 离散数据\n",
    "- 需要精确计数\n",
    "- 数据量较小\n",
    "- 需要明确区间\n",
    "\n",
    "### 最佳实践\n",
    "\n",
    "- 先用默认参数快速查看\n",
    "- 根据数据特点调整带宽\n",
    "- 多组对比时使用填充和透明度\n",
    "- 结合累积分布进行深入分析\n",
    "- 双变量 KDE 可展示联合分布"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
